package com.victualler.core.common.utils;



import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonTypeInfo.As;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.text.SimpleDateFormat;
import java.util.List;

import org.springframework.beans.BeanUtils;

public class JsonUtil {
    private static ObjectMapper obj = new ObjectMapper();

    public static String toJsonString(Object o, Boolean prettyFormat) {
        return toJsonString(o, prettyFormat, Boolean.valueOf(false));
    }

    public static String toJsonString(Object o, Boolean prettyFormat, Boolean enableDefaultTyping) {
        return toJsonString(o, prettyFormat, enableDefaultTyping, Boolean.valueOf(false));
    }

    public static String toJsonString(Object o, Boolean prettyFormat, Boolean enableDefaultTyping,
                                      Boolean disableMapNull) {
        try {
            obj.configure(SerializationFeature.INDENT_OUTPUT, true);
            if (disableMapNull.booleanValue()) {
                obj.disable(SerializationFeature.WRITE_NULL_MAP_VALUES);
            }
            obj.setSerializationInclusion(Include.NON_NULL);
            obj.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
            obj.setDateFormat(sdf);
            if (enableDefaultTyping.booleanValue()) {
                obj.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, As.PROPERTY);
            } else {
                obj.disableDefaultTyping();
            }
            return obj.writeValueAsString(o);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static <T> T toJavaObject(String json, Class<T> valueType) throws JsonParseException, JsonMappingException, IOException {
        return toJavaObject(json, valueType, Boolean.valueOf(false));
    }

    public static <T> T toJavaObject(String json, Class<T> valueType, Boolean enableDefaultTyping) throws JsonParseException, JsonMappingException, IOException {
        
            if (enableDefaultTyping.booleanValue()) {
                obj.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, As.PROPERTY);
            } else {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
                obj.setDateFormat(sdf);
                obj.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
                obj.enable(DeserializationFeature.USE_LONG_FOR_INTS);
                obj.disableDefaultTyping();
            }
            return obj.readValue(json, valueType);
        
       
    }

    public static <T> List<T> toJavaList(String json, Class<T> valueType) {
        return toJavaList(json, valueType, Boolean.valueOf(false));
    }

    public static <T> List<T> toJavaList(String json, Class<T> valueType, Boolean enableDefaultTyping) {
        try {
            JavaType javaType = obj.getTypeFactory().constructParametrizedType(List.class, List.class,
                    new Class[] { valueType });
            if (enableDefaultTyping.booleanValue()) {
                obj.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL, As.PROPERTY);
            } else {
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
                obj.setDateFormat(sdf);
                obj.enable(DeserializationFeature.USE_BIG_DECIMAL_FOR_FLOATS);
                obj.enable(DeserializationFeature.USE_LONG_FOR_INTS);
                obj.disableDefaultTyping();
            }
            return (List) obj.readValue(json, javaType);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    
    public static <T> T toJavaObject(Object o, Class<T> valueType) {
        try {
            T target = valueType.newInstance();
            BeanUtils.copyProperties(o, target);
            return target;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }
}
